package com.lambda.plugin;

import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.File;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class GenerateAction implements Action<Task> {
    private final float mDefaultDimen = 360;
    private final Project mProject;
    private final DimensConfig mConfig;
    private String mVariant;
    private String mFlavor;

    GenerateAction(Project project, DimensConfig config) {
        mProject = project;
        mConfig = config;
    }

    @Override
    public void execute(@NotNull Task task) {
        List<Integer> targetScreenDp = mConfig.screenDp;
        if (targetScreenDp == null || targetScreenDp.size() == 0)
            return;

        final String absoluteProjectDir = mProject.getProjectDir().getAbsolutePath();
        final String defaultDimensFileString = absoluteProjectDir + "/src/main/res/values/dimens.xml";
        final File defaultDimensFile = new File(replaceSeparator(defaultDimensFileString));
        if (!defaultDimensFile.exists()) {
            throw new GradleException("默认文件不存在（" + defaultDimensFileString + "）");
        }

        final String buildPath = mProject.getBuildDir().getAbsolutePath() + "/generated/res/resValues/%s";
        try {
            for (Integer dimen : targetScreenDp) {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document documentIn = builder.parse(defaultDimensFile);
                Document documentOut = builder.newDocument();

                String path;
                if (mFlavor == null) {
                    path = mVariant;
                } else {
                    path = mFlavor + File.separator + mVariant;
                }

                String fileOut = replaceSeparator(String.format(buildPath + "/values-sw" + dimen + "dp", path));
                generate(documentIn, documentOut, fileOut, dimen);
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }

    private void generate(Document documentIn, Document documentOut, String fout, int dimen) {
        try {
            documentOut.setXmlStandalone(true);
            final Element rootElementOut = documentOut.createElement("resources");
            documentOut.appendChild(rootElementOut);

            NodeList dimenList = documentIn.getElementsByTagName("dimen");
            for (int i = 0; i < dimenList.getLength(); i++) {
                final Element dimenElement = (Element) dimenList.item(i);
                final Element targetElement = documentOut.createElement("dimen");
                rootElementOut.appendChild(targetElement);

                final Attr attr = dimenElement.getAttributeNode("name");
                final Attr targetAttr = documentOut.createAttribute("name");
                targetAttr.setValue(attr.getValue());
                targetElement.setAttributeNode(targetAttr);

                String dimenContent = dimenElement.getTextContent();
                dimenContent = calc(dimenContent, dimen, mDefaultDimen);
                targetElement.setTextContent(dimenContent);
            }

            Source source = new DOMSource(rootElementOut);
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

            File targetDimensDir = new File(fout);
            if (!targetDimensDir.exists() && !targetDimensDir.mkdirs()) {
                throw new GradleException("无法创建目录（" + targetDimensDir + "）");
            }

            File targetDimensFile = new File(targetDimensDir, "dimen.xml");
            if (targetDimensFile.exists() && !targetDimensFile.delete()) {
                throw new GradleException("无法删除旧的文件（" + targetDimensFile + "）");
            }

            if (!targetDimensFile.createNewFile()) {
                throw new GradleException("无法创建新文件（" + targetDimensFile + "）");
            }

            Result result = new StreamResult(targetDimensFile);
            transformer.transform(source, result);
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }

    void setVariant(String variant) {
        byte[] bytes = variant.getBytes();
        bytes[0] += 32;
        int i;
        for (i = 1; i < bytes.length; i += 1) {
            final int b = bytes[i];
            if (b >= 'A' && b <= 'Z') {
                bytes[i] += 32;
                break;
            }
        }
        if (i < bytes.length) {
            mFlavor = new String(bytes, 0, i);
            mVariant = new String(bytes, i, bytes.length - i);
        } else {
            mVariant = new String(bytes);
        }
    }

    private static String calc(String dimenString, float targetDimen, float defaultDimen) {
        String num = dimenString.substring(0, dimenString.length() - 2);
        float dimen = Float.parseFloat(num);
        return (dimen * targetDimen / defaultDimen) + dimenString.substring(num.length());
    }

    private static String replaceSeparator(String path) {
        return path.replace('/', File.separatorChar);
    }
}
